package com.fastwire.carriere.controller.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.fastwire.carriere.common.Messages;
import com.fastwire.carriere.common.constant.AppConstants;
import com.fastwire.carriere.common.constant.HuaweiInventoryConstants;
import com.fastwire.carriere.common.exception.ResourceException;
import com.fastwire.carriere.common.mapper.CardBandwidthMapper;
import com.fastwire.carriere.common.mapper.NENameMapper;
import com.fastwire.carriere.common.mapper.TPNameMapper;
import com.fastwire.carriere.common.util.StringUtil;
import com.fastwire.carriere.controller.CrossConnectController;
import com.fastwire.carriere.dao.CrossConnectBandwidthDao;
import com.fastwire.carriere.dao.CrossConnectDao;
import com.fastwire.carriere.dao.DAOException;
import com.fastwire.carriere.dao.DAOFactory;
import com.fastwire.carriere.dao.FDFRDao;
import com.fastwire.carriere.dao.NetworkInventoryDao;
import com.fastwire.carriere.dao.ProtectionGroupDao;
import com.fastwire.carriere.dao.TPDao;
import com.fastwire.carriere.hibernate.daoimpl.NetworkInventoryDaoImpl;
import com.fastwire.carriere.inventory.entity.CrossConnect;
import com.fastwire.carriere.inventory.entity.CrossConnectBandwidth;
import com.fastwire.carriere.inventory.entity.FDFr;
import com.fastwire.carriere.inventory.entity.NetworkElement;
import com.fastwire.carriere.inventory.entity.NetworkEntityUserSpecificInfo;
import com.fastwire.carriere.inventory.entity.ProtectionGroup;
import com.fastwire.carriere.inventory.entity.TerminationPoint;
import com.fastwire.carriere.inventory.entity.TransmissionParameter;
import com.fastwire.carriere.inventory.vo.ConnectivityVo;
import com.fastwire.carriere.inventory.vo.CrossConnectVo;
import com.fastwire.carriere.inventory.vo.EndVo;
import com.fastwire.carriere.rad.controller.RadProcessController;
import com.fastwire.carriere.rad.controller.RadProcessControllerImp;
import com.fastwire.carriere.rad.entity.Rad;
import com.fastwire.carriere.rad.entityVo.RadVo;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;

public class CrossConnectControllerImpl implements CrossConnectController {

	/** The cc dao. */
	private final CrossConnectDao ccDao = DAOFactory.getInstance()
			.getCrossConnectDao();

	private final CrossConnectBandwidthDao ccBandwidthDao = DAOFactory
			.getInstance().getCrossConnectBandwidthDao();

	/** The fdfr dao. */
	private final FDFRDao fdfrDao = DAOFactory.getInstance().getFdfrDao();

	/** The tp dao. */
	private final TPDao tpDao = DAOFactory.getInstance().getTPDao();

	private final NetworkInventoryDao inventoryDao = new NetworkInventoryDaoImpl();

	/**
	 * Stitch cross connect.
	 * 
	 * @param ccList
	 *            the cc list
	 * @param pathType
	 *            the path type
	 * @return the list
	 * @throws ResourceException
	 *             the resource exception
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<ConnectivityVo> stitchCrossConnect(List<CrossConnect> ccList,
			String pathType) throws ResourceException, DAOException {

		CrossConnect header = null;

		for (CrossConnect cc : ccList) {
			if (StringUtil.isEmptyString(cc.getAendTp().getName())
					&& !StringUtil.isEmptyString(cc.getZendTp().getName())) {
				header = cc;
			}

		}

		if (header != null) {
			removeCC(ccList, header.getName());
		} else {
			throw new ResourceException(Messages.getString(
					"message.crossconnect.headernode.notexistent",
					new String[] { "tunnel" }));
		}

		List<ConnectivityVo> connectivityVos = Lists.newArrayList();

		NetworkElement firstNE = NENameMapper.getNEbyU2kName(header.getName());
		long bandwidth = getTunnelBandwidth(ccList);

		int loopCount = 50;

		while (ccList.size() > 0) {

			ConnectivityVo connectivityVo = new ConnectivityVo();
			connectivityVo.setName(header.getEmsNativeName());
			connectivityVo.setaEnd(firstNE, header);
			connectivityVo.setPathType(pathType);

			TerminationPoint nextHopTP = tpDao.findTPbyIPAddress(header
					.getNextHop());

			String aendTp = TPNameMapper.getReadableTpName(header.getZendTp()
					.getName(), header.getZendTp().getType(), firstNE);
			connectivityVo.setAendTp(aendTp);
			connectivityVo.setDirectionality(header.getDirection());
			connectivityVo.setBandwidth(String.valueOf(bandwidth));
			String outLabel = TPNameMapper.getCTPLabel(header.getZendTp()
					.getName());

			for (CrossConnect cc : ccList) {
				String inlabel = TPNameMapper.getCTPLabel(cc.getAendTp()
						.getName());
				String currNEName = NENameMapper.getNEIdbyName(cc.getName());

				if (inlabel.equals(outLabel)
						&& ((nextHopTP != null && nextHopTP.getNeName().equals(
								currNEName))
								|| ccList.size() == 1 || nextHopTP == null)) {
					NetworkElement nextNE = NENameMapper
							.getNEbyName(currNEName);
					connectivityVo.setzEnd(nextNE, cc);

					String zendTp = TPNameMapper.getReadableTpName(cc
							.getAendTp().getName(), cc.getAendTp().getType(),
							nextNE);
					connectivityVo.setZendTp(zendTp);
					removeCC(ccList, cc.getName());
					connectivityVos.add(connectivityVo);
					firstNE = nextNE;
					header = cc;

					break;

				}

			}

			connectivityVo.setBandwidthSetting(CardBandwidthMapper
					.getBandwidth(connectivityVo.getAendTp(),
							connectivityVo.getZendTp()));

			// we will add a flag to avoid the dead-loop caused by duplicated
			// crossconnect issue
			// in U2000
			if (--loopCount == 0) {
				break;
			}

		}

		return connectivityVos;

	}

	/**
	 * Group c cby slot and port.
	 * 
	 * @param neID
	 *            the ne id
	 * @return the hash multimap
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public HashMultimap<String, CrossConnectVo> groupCCbySlotAndPort(String neID)
			throws DAOException {

		List<CrossConnect> ccList = DAOFactory.getInstance()
				.getCrossConnectDao().getCrossConnectsbyNE(neID);
		HashMultimap<String, CrossConnectVo> ccslotMap = HashMultimap.create();

		for (CrossConnect cc : ccList) {

			CrossConnectVo ccVo = new CrossConnectVo(cc);
			String aendKey = TPNameMapper
					.getTPHashKey(cc.getAendTp().getName());
			String zendKey = TPNameMapper
					.getTPHashKey(cc.getZendTp().getName());

			if (!StringUtil.isEmptyString(aendKey)) {
				ccslotMap.put(aendKey, ccVo);
			}

			if (!StringUtil.isEmptyString(zendKey)) {
				ccslotMap.put(zendKey, ccVo);
			}

		}

		return ccslotMap;

	}

	/**
	 * Gets the maximum bandwidth.
	 * 
	 * @param ccName
	 *            the cc name
	 * @return the maximum bandwidth
	 */
	@Override
	public int getTunnelBandwidth(List<CrossConnect> ccList) {

		int bandwidth = 0;

		for (CrossConnect cc : ccList) {
			TransmissionParameter tParameter = cc
					.getTransmissionParameterbyLR(HuaweiInventoryConstants.LayerRate_MPLS_Path);

			int bandwidthPara = tParameter.getBandwidth();

			bandwidth = Math.max(bandwidthPara, bandwidth);

		}

		if (bandwidth == 0 && ccList.size() > 0) {
			bandwidth = Integer.valueOf(getTunnelbandwidthbyName(ccList.get(0)
					.getEmsNativeName()));
		}
		return bandwidth;

	}

	/**
	 * Gets the protection groupby tunnel name.
	 * 
	 * @param tunnelName
	 *            the tunnel name
	 * @return the protection groupby tunnel name
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public HashMap<String, String> getProtectionGroupbyTunnelName(
			String tunnelName) throws DAOException {
		DAOFactory daoFactory = DAOFactory.getInstance();
		CrossConnectDao ccDao = daoFactory.getCrossConnectDao();
		List<CrossConnect> ccList = ccDao.getCrossConnectsbyName(tunnelName);
		String neID = null;

		HashMap<String, String> pgMap = new HashMap<String, String>();
		for (CrossConnect cc : ccList) {
			String ccName = cc.getName();

			neID = NENameMapper.getNEIdbyName(ccName);

			ProtectionGroup pGroup = daoFactory.getProtectionGroupDao()
					.findProtectionGroupbyMemberName(ccName, neID);

			if (pGroup != null) {

				pgMap.put(AppConstants.WORKING, pGroup.getWorking());
				pgMap.put(AppConstants.WORKING_RVS, pGroup.getWorkingReverse());
				pgMap.put(AppConstants.PRT, pGroup.getProtection());
				pgMap.put(AppConstants.PRT_RVS, pGroup.getProtectionReverse());

				break;

			}

		}
		for (Entry<String, String> entry : pgMap.entrySet()) {
			String value = entry.getValue();
			CrossConnect cc = ccDao.getCrossConnectsbyNEAndName(value, neID);
			pgMap.put(entry.getKey(), cc.getEmsNativeName());

		}

		return pgMap;
	}

	@Override
	public HashMap<String, String> getProtectionGroupbyTunnelName(
			List<String> tunnelList) throws DAOException {
		HashMap<String, String> pgMap = new HashMap<String, String>();

		if (tunnelList.size() == 0) {
			return pgMap;
		}
		DAOFactory daoFactory = DAOFactory.getInstance();
		CrossConnectDao ccDao = daoFactory.getCrossConnectDao();
		List<CrossConnect> ccList = ccDao.getCrossConnectsbyName(tunnelList
				.get(0));
		String neID = null;

		for (CrossConnect cc : ccList) {
			String ccName = cc.getName();

			neID = NENameMapper.getNEIdbyName(ccName);

			ProtectionGroup pGroup = daoFactory.getProtectionGroupDao()
					.findProtectionGroupbyMemberName(ccName, neID);

			if (pGroup != null) {

				pgMap.put(AppConstants.WORKING, pGroup.getWorking());
				pgMap.put(AppConstants.WORKING_RVS, pGroup.getWorkingReverse());
				pgMap.put(AppConstants.PRT, pGroup.getProtection());
				pgMap.put(AppConstants.PRT_RVS, pGroup.getProtectionReverse());

				break;

			}

		}

		if (pgMap.size() == 0) {
			pgMap.put(AppConstants.WORKING, tunnelList.get(0));
			pgMap.put(AppConstants.WORKING_RVS, tunnelList.get(1));

		}

		for (Entry<String, String> entry : pgMap.entrySet()) {
			String value = entry.getValue();
			CrossConnect cc = ccDao.getCrossConnectsbyNEAndName(value, neID);
			pgMap.put(entry.getKey(), cc.getEmsNativeName());

		}

		return pgMap;
	}

	/**
	 * Gets the cross connectby ne id.
	 * 
	 * @param neId
	 *            the ne id
	 * @return the cross connectby ne id
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<CrossConnectVo> getCrossConnectbyNeId(String neId)
			throws DAOException {

		List<CrossConnect> ccList = ccDao.getCrossConnectsbyNE(neId);

		List<CrossConnectVo> ccVoList = Lists.newArrayList();

		for (CrossConnect cc : ccList) {
			ccVoList.add(new CrossConnectVo(cc));
		}

		return ccVoList;

	}

	/**
	 * Search cross connect.
	 * 
	 * @param searchVo
	 *            the search vo
	 * @return the list
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<String> searchCrossConnect(CrossConnectVo searchVo)
			throws DAOException {

		List<String> ccList = ccDao.getCrossConnectsbyVo(searchVo);

		return ccList;

	}

	/**
	 * Stitch tunnel.
	 * 
	 * @param nativeEMSName
	 *            the native ems name
	 * @return the list
	 * @throws ResourceException
	 *             the resource exception
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<ConnectivityVo> stitchTunnel(String nativeEMSName)
			throws ResourceException, DAOException {

		String pathType = "main";

		List<CrossConnect> ccList = ccDao.getCrossConnectsbyName(nativeEMSName);

		ProtectionGroupDao pgDao = DAOFactory.getInstance()
				.getProtectionGroupDao();
		HashMap<String, String> pgMap = new HashMap<String, String>();
		for (CrossConnect cc : ccList) {
			String ccName = cc.getName();

			String neID = NENameMapper.getNEIdbyName(ccName);

			ProtectionGroup pGroup = pgDao.findProtectionGroupbyMemberName(
					ccName, neID);

			if (pGroup != null) {

				pgMap.put(AppConstants.WORKING, pGroup.getWorking());
				pgMap.put(AppConstants.WORKING_RVS, pGroup.getWorkingReverse());
				pgMap.put(AppConstants.PRT, pGroup.getProtection());
				pgMap.put(AppConstants.PRT_RVS, pGroup.getProtectionReverse());

				break;

			}

		}

		for (Entry<String, String> entry : pgMap.entrySet()) {
			String value = entry.getValue();
			for (CrossConnect cc : ccList) {
				if (value.equals(cc.getName())) {
					entry.setValue(cc.getEmsNativeName());
					break;
				}
			}

		}

		if (nativeEMSName.equals(pgMap.get(AppConstants.PRT))
				|| nativeEMSName.equals(pgMap.get(AppConstants.PRT_RVS))) {
			pathType = "standby";
		}

		return stitchCrossConnect(ccList, pathType);
	}

	
	
	//---------------------------------------------------------------------------------------------;
	// added by Jun on 20120509
	@Override
	public List<ConnectivityVo> stitchRad(List<ConnectivityVo> conList) throws ResourceException, DAOException 
	{
        RadProcessController radCtrl = new RadProcessControllerImp();

        conList = radCtrl.stitchRad(conList);
    
	    return conList;
	}
	
	
	/**
	 * Gets the cross connectby name and ne.
	 * 
	 * @param nativeEmsName
	 *            the native ems name
	 * @param neId
	 *            the ne id
	 * @return the cross connectby name and ne
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public CrossConnectVo getCrossConnectbyNameAndNE(String nativeEmsName,
			String neId) throws DAOException {

		CrossConnect crossConnect = ccDao
				.getCrossConnectsbyNativeEmsNameAndNEId(nativeEmsName, neId);
		return new CrossConnectVo(crossConnect);
	}

	/**
	 * Gets the cross connectsby native name list and ne id.
	 * 
	 * @param nativeEmsNames
	 *            the native ems names
	 * @param neId
	 *            the ne id
	 * @return the cross connectsby native name list and ne id
	 * @throws DAOException
	 *             the dAO exception
	 */
	@Override
	public List<CrossConnectVo> getCrossConnectsbyNativeNameListAndNeId(
			String[] nativeEmsNames, String neId) throws DAOException {

		List<String> nativeEmsNameList = null;
		if (!StringUtil.isNullOrEmpty(nativeEmsNames)) {
			nativeEmsNameList = Arrays.asList(nativeEmsNames);
		}
		List<CrossConnect> ccList = ccDao
				.getCrossConnectListsbyNEAndEmsnativeName(nativeEmsNameList,
						neId);

		List<CrossConnectVo> ccVoList = Lists.newArrayList();

		for (CrossConnect cc : ccList) {
			ccVoList.add(new CrossConnectVo(cc));
		}

		return ccVoList;

	}

	/**
	 * Gets the tunnel graphsby fd fr name.
	 * 
	 * @param fdfrName
	 *            the fdfr name
	 * @return the tunnel graphsby fd fr name
	 * @throws DAOException
	 *             the dAO exception
	 * @throws ResourceException
	 *             the resource exception
	 */
	@Override
	public List<ConnectivityVo> getTunnelGraphsbyFDFrName(String fdfrName)
			throws DAOException, ResourceException {
		List<FDFr> fdFrList = fdfrDao.findFdFrbyEmsNativeName(fdfrName);

		List<String> tunnelNameList = new ArrayList<String>();

		Pattern pattern = Pattern
				.compile(".*TUNNEL=(.*|.*|.*|.*|\\d+\\|\\|)\\d+");

		for (FDFr fdfr : fdFrList) {
			Set<TransmissionParameter> transParameters = fdfr.getZendTp()
					.getTransParameters();

			for (TransmissionParameter transParameter : transParameters) {
				String tunnelName = transParameter
						.getParameter(HuaweiInventoryConstants.FDFR_BindingObject);

				if (!StringUtil.isEmptyString(tunnelName)) {
					Matcher matcher = pattern.matcher(tunnelName);
					if (matcher.matches()
							& !tunnelNameList.contains(matcher.group(1))) {
						tunnelNameList.add(matcher.group(1));
					}
				}
			}
		}
		if (!tunnelNameList.isEmpty()) {
			String serviceID = tunnelNameList.get(0);

			HashMap<String, String> pgGroup = getProtectionGroupbyTunnelName(serviceID);

			List<ConnectivityVo> connectivityVos = Lists.newArrayList();

			if (pgGroup.size() > 0) {
				for (Entry<String, String> pgEntry : pgGroup.entrySet()) {
					String ccName = pgEntry.getValue();
					String keyName = pgEntry.getKey();
					List<CrossConnect> ccList = ccDao
							.getCrossConnectsbyName(ccName);
					List<ConnectivityVo> conVos = stitchCrossConnect(ccList,
							keyName);
					connectivityVos.addAll(conVos);
				}
			} else {

				for (String tunnelNameStr : tunnelNameList) {
					List<CrossConnect> ccList = ccDao
							.getCrossConnectsbyName(tunnelNameStr);
					List<ConnectivityVo> conVos = stitchCrossConnect(ccList,
							"main");
					connectivityVos.addAll(conVos);
				}
			}

			return connectivityVos;
		} else {
			throw new ResourceException("cannot find tunnels");

		}

	}

	@Override
	public void updateTunnel(CrossConnectVo ccVo) throws DAOException {

		NetworkEntityUserSpecificInfo neUserSpecificInfo = inventoryDao
				.getNetworkEntityUserSpecificInfobyNameAndType(
						ccVo.getNativeEmsName(),
						CrossConnect.class.getSimpleName());

		if (neUserSpecificInfo == null) {
			neUserSpecificInfo = new NetworkEntityUserSpecificInfo();
			neUserSpecificInfo.setName(ccVo.getNativeEmsName());
			neUserSpecificInfo.setType(FDFr.class.getSimpleName());

		}

		neUserSpecificInfo.setRemark(ccVo.getRemarks());

		inventoryDao
				.saveOrUpdateNetworkEntityUserSpecificInfo(neUserSpecificInfo);

	}

	private void removeCC(List<CrossConnect> ccList, String ccName) {
		List<CrossConnect> ccRemoveList = Lists.newArrayList();
		for (CrossConnect cc : ccList) {

			if (ccName.equals(cc.getName())) {
				ccRemoveList.add(cc);
			}
		}

		ccList.removeAll(ccRemoveList);

	}

	public static String getTunnelbandwidthbyName(String emsNativeName) {

		String bandwidth = "0";
		Pattern pattern = Pattern
				.compile(".*-.*-M\\d+-(\\d+)([MGHE][EX]?)-\\d+.*");
		Matcher matcher = pattern.matcher(emsNativeName);

		if (matcher.matches()) {
			int multiplier = Integer.valueOf(matcher.group(1));
			String identifier = matcher.group(2);
			if (HuaweiInventoryConstants.BANDWIDTH_KEYWORD_MAP
					.containsKey(identifier)) {
				int unit = HuaweiInventoryConstants.BANDWIDTH_KEYWORD_MAP
						.get(identifier);

				int totalBandwidth = multiplier * unit;

				if (HuaweiInventoryConstants.BANDWIDTH_CIR_MAP
						.containsKey(totalBandwidth)) {
					bandwidth = String
							.valueOf(HuaweiInventoryConstants.BANDWIDTH_CIR_MAP
									.get(totalBandwidth));
				} else {

					int sowBadnwidth = (int) (totalBandwidth * 1000 / 0.7369 + 200);
					bandwidth = String.valueOf(Math.min(1000000, sowBadnwidth));
				}

			}

		}

		return bandwidth;

	}

	@Override
	public int getBandwidthbyTunnelNameList(List<String> ccNameList)
			throws DAOException {

		int totalBandwidth = 0;
		// ??? 
		// remove the loop, and use the hibernate in criteria : in   
		for (String cc : ccNameList) {

			// in
			CrossConnectBandwidth ccBandwidth = ccBandwidthDao
					.getCrossConnectBandwidthbyName(cc);

			// modified by Jun on 20120509
			if(null != ccBandwidth)
			{
    			if (ccBandwidth.getMaxbandwidth() > 0) {
    				totalBandwidth += ccBandwidth.getMaxbandwidth();
    			} else if (ccBandwidth.getMaxbandwidth() == 0) {
    
    				String bandwidthByName = getTunnelbandwidthbyName(ccBandwidth
    						.getEmsNativeName());
    				if (bandwidthByName != null)
    					totalBandwidth += Integer.valueOf(bandwidthByName);
    			}
    
    			if (totalBandwidth > 0) {
    				break;
    			}
			}
		}

		return totalBandwidth;
	}
}
